using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;

using GURUCORE.Framework.Core;
using GURUCORE.Framework.Core.Proxy;

namespace GURUCORE.Framework.Business
{
	public class ServiceClassLoader
	{
		public static Hashtable m_htProxyTypeCache = new Hashtable();
		private static object m_oLock = new object();

		public static T CreateInstance<T>() where T : class
		{
			const string PROXY_CLASS_SUFFIX = "_Proxy_";

			T oInstance;
			Type tOriginalType = typeof(T);

			try
			{
				IMethodInvocation oMethodInvocation = new BusinessMethodInvocation();

				object[] arrAttr = tOriginalType.Assembly.GetCustomAttributes(typeof(System.Runtime.InteropServices.GuidAttribute), false);
				if (arrAttr.Length == 1)
				{
					oMethodInvocation.ModuleID = ((System.Runtime.InteropServices.GuidAttribute)arrAttr[0]).Value;
				}

				Type tProxyType;
				object oBaseInstance = Activator.CreateInstance(typeof(T));

				if (!m_htProxyTypeCache.ContainsKey(tOriginalType.FullName + PROXY_CLASS_SUFFIX))
				{
					lock (m_oLock)
					{
						DynamicProxy oDynamicProxy = new DynamicProxy();
						tProxyType = oDynamicProxy.GetProxyClass(typeof(T), new Type[0], MethodAttributeSemantics.AttributeDisablesController);
						m_htProxyTypeCache.Add(tOriginalType.FullName + PROXY_CLASS_SUFFIX, tProxyType);
					}
				}
				else
				{
					tProxyType = (Type)m_htProxyTypeCache[tOriginalType.FullName + PROXY_CLASS_SUFFIX];
				}

				oInstance = (T)Activator.CreateInstance(tProxyType, new object[] 
				{
					oBaseInstance,
					oMethodInvocation
				});
			}
			
			catch (Exception ex)
			{
				oInstance = (T)Activator.CreateInstance(tOriginalType, null);
			}

			return oInstance;
		}

		internal static object CreateInstance(Type p_tType)
		{
			const string PROXY_CLASS_SUFFIX = "_Proxy_";

            Type tProxyType = null;
            // DEBUG: proxy bug, put try catch here to determine is the bug here?
            try
            {
                IMethodInvocation oMethodInvocation = new BusinessMethodInvocation();
                Type tOriginalType = p_tType;

                object[] arrAttr = tOriginalType.Assembly.GetCustomAttributes(typeof(System.Runtime.InteropServices.GuidAttribute), false);
                if (arrAttr.Length == 1)
                {
                    oMethodInvocation.ModuleID = ((System.Runtime.InteropServices.GuidAttribute)arrAttr[0]).Value;
                }

                
                object oBaseInstance = Activator.CreateInstance(tOriginalType);
                if (!m_htProxyTypeCache.ContainsKey(tOriginalType.FullName + PROXY_CLASS_SUFFIX))
                {
                    lock (m_oLock)
                    {
                        DynamicProxy oDynamicProxy = new DynamicProxy();
                        tProxyType = oDynamicProxy.GetProxyClass(tOriginalType, new Type[0], MethodAttributeSemantics.AttributeDisablesController);

                        // thread problem, dont remove this if else (redundant with outside if else
                        if (!m_htProxyTypeCache.ContainsKey(tOriginalType.FullName + PROXY_CLASS_SUFFIX))
                        {
                            m_htProxyTypeCache.Add(tOriginalType.FullName + PROXY_CLASS_SUFFIX, tProxyType);
                        }
                        else
                        {
                            tProxyType = (Type)m_htProxyTypeCache[tOriginalType.FullName + PROXY_CLASS_SUFFIX];
                        }
                    }
                }
                else
                {
                    tProxyType = (Type)m_htProxyTypeCache[tOriginalType.FullName + PROXY_CLASS_SUFFIX];
                }

                object oInstance = Activator.CreateInstance(tProxyType,
                    new object[] {oBaseInstance,oMethodInvocation}
                );

                return oInstance;
            }
            catch(Exception ex)
            {
				return Activator.CreateInstance(tProxyType, null);
                //throw new FrameworkException("ERROR at ServiceClassLoader.CreateInstance("+p_tType.FullName+")", ex);
            }
		}


	}
}
